home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / Class2Ersatz.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  7KB  |  245 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/Class2Ersatz.c++,v 1.6 1994/03/09 19:24:27 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include "Class2Ersatz.h"
  26. #include "ModemConfig.h"
  27.  
  28. #include <stdlib.h>
  29. #include <ctype.h>
  30.  
  31. Class2ErsatzModem::Class2ErsatzModem(FaxServer& s, const ModemConfig& c)
  32.     : Class2Modem(s,c)
  33. {
  34.     serviceType = SERVICE_CLASS2;
  35.     setupDefault(classCmd,    conf.class2Cmd,        "+FCLASS=2");
  36.     setupDefault(mfrQueryCmd,    conf.mfrQueryCmd,    "+FMFR?");
  37.     setupDefault(modelQueryCmd,    conf.modelQueryCmd,    "+FMDL?");
  38.     setupDefault(revQueryCmd,    conf.revQueryCmd,    "+FREV?");
  39.     setupDefault(dccQueryCmd,    conf.class2DCCQueryCmd, "+FDCC=?");
  40.     setupDefault(abortCmd,    conf.class2AbortCmd,    "K");
  41.  
  42.     setupDefault(borCmd,    conf.class2BORCmd,    "BOR=0");
  43.     setupDefault(tbcCmd,    conf.class2TBCCmd,    "TBC=0");
  44.     setupDefault(crCmd,        conf.class2CRCmd,    "CR=1");
  45.     setupDefault(phctoCmd,    conf.class2PHCTOCmd,    "PHCTO=30");
  46.     setupDefault(bugCmd,    conf.class2BUGCmd,    "BUG=1");
  47.     setupDefault(lidCmd,    conf.class2LIDCmd,    "LID");
  48.     setupDefault(dccCmd,    conf.class2DCCCmd,    "DCC");
  49.     setupDefault(disCmd,    conf.class2DISCmd,    "DIS");
  50.     setupDefault(cigCmd,    conf.class2CIGCmd,    "CIG");
  51.     setupDefault(splCmd,    conf.class2SPLCmd,    "SPL");
  52. }
  53.  
  54. Class2ErsatzModem::~Class2ErsatzModem()
  55. {
  56. }
  57.  
  58. ATResponse
  59. Class2ErsatzModem::atResponse(char* buf, long ms)
  60. {
  61.     if (FaxModem::atResponse(buf, ms) == AT_OTHER &&
  62.       (buf[0] == '+' && buf[1] == 'F')) {
  63.     if (strneq(buf, "+FHNG:", 6)) {
  64.         processHangup(buf+6);
  65.         lastResponse = AT_FHNG;
  66.     } else if (strneq(buf, "+FCON", 5))
  67.         lastResponse = AT_FCON;
  68.     else if (strneq(buf, "+FPOLL", 6))
  69.         lastResponse = AT_FPOLL;
  70.     else if (strneq(buf, "+FDIS:", 6))
  71.         lastResponse = AT_FDIS;
  72.     else if (strneq(buf, "+FNSF:", 6))
  73.         lastResponse = AT_FNSF;
  74.     else if (strneq(buf, "+FCSI:", 6))
  75.         lastResponse = AT_FCSI;
  76.     else if (strneq(buf, "+FPTS:", 6))
  77.         lastResponse = AT_FPTS;
  78.     else if (strneq(buf, "+FDCS:", 6))
  79.         lastResponse = AT_FDCS;
  80.     else if (strneq(buf, "+FNSS:", 6))
  81.         lastResponse = AT_FNSS;
  82.     else if (strneq(buf, "+FTSI:", 6))
  83.         lastResponse = AT_FTSI;
  84.     else if (strneq(buf, "+FET:", 5))
  85.         lastResponse = AT_FET;
  86.     }
  87.     return (lastResponse);
  88. }
  89.  
  90. /*
  91.  * Handle the page-end protocol.
  92.  */
  93. fxBool
  94. Class2ErsatzModem::pageDone(u_int ppm, u_int& ppr)
  95. {
  96.     ppr = 0;            // something invalid
  97.     if (vatFaxCmd(AT_NOTHING, "ET=%u", ppm)) {
  98.     for (;;) {
  99.         switch (atResponse(rbuf, conf.pageDoneTimeout)) {
  100.         case AT_FPTS:
  101.         if (sscanf(rbuf+6, "%u,", &ppr) != 1) {
  102.             protoTrace("MODEM protocol botch (\"%s\"), %s",
  103.             rbuf, "can not parse PPR");
  104.             return (FALSE);        // force termination
  105.         }
  106.         break;
  107.         case AT_OK:                // normal result code
  108.         case AT_ERROR:            // possible if page retransmit
  109.         return (TRUE);
  110.         case AT_FHNG:
  111.         return (isNormalHangup());
  112.         case AT_EMPTYLINE:
  113.         /*
  114.          * The ZyXEL modem appears to drop DCD when the
  115.          * remote side drops carrier, no matter whether
  116.          * DCD is configured to follow carrier or not.
  117.          * This results in a stream of empty lines,
  118.          * *sometimes* followed by the requisite trailing OK.
  119.          * As a hack workaround to deal with the situation
  120.          * we accept the post page response if this is the
  121.          * last page that we're sending and the page is
  122.          * good (i.e. we would hang up immediately anyway).
  123.          */
  124.         if (ppm == PPM_EOP && ppr == PPR_MCF)
  125.             return (TRUE);
  126.         /* fall thru... */
  127.         case AT_TIMEOUT:
  128.         case AT_NOCARRIER:
  129.         case AT_NODIALTONE:
  130.         case AT_NOANSWER:
  131.         goto bad;
  132.         }
  133.     }
  134.     }
  135. bad:
  136.     processHangup("50");        // Unspecified Phase D error
  137.     return (FALSE);
  138. }
  139.  
  140. /*
  141.  * Abort a data transfer in progress.
  142.  */
  143. void
  144. Class2ErsatzModem::abortDataTransfer()
  145. {
  146.     char c = CAN;
  147.     putModemData(&c, 1);
  148. }
  149.  
  150. /*
  151.  * Send an end-of-transmission signal to the modem.
  152.  */
  153. fxBool
  154. Class2ErsatzModem::sendEOT()
  155. {
  156.     static char EOT[] = { DLE, ETX };
  157.     return (putModemData(EOT, sizeof (EOT)));
  158. }
  159.  
  160. /*
  161.  * Send a page of data using the ``stream interface''.
  162.  */
  163. fxBool
  164. Class2ErsatzModem::sendPage(TIFF* tif)
  165. {
  166.     fxBool rc = TRUE;
  167.     protoTrace("SEND begin page");
  168.     if (flowControl == FLOW_XONXOFF)
  169.     setXONXOFF(FLOW_XONXOFF, FLOW_NONE, ACT_FLUSH);
  170.     /*
  171.      * Correct bit order of data if not what modem expects.
  172.      */
  173.     u_short fillorder;
  174.     TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
  175.     const u_char* bitrev = TIFFGetBitRevTable(fillorder != conf.sendFillOrder);
  176.  
  177.     u_long* stripbytecount;
  178.     (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbytecount);
  179.     for (u_int strip = 0; strip < TIFFNumberOfStrips(tif) && rc; strip++) {
  180.     u_int totbytes = (u_int) stripbytecount[strip];
  181.     if (totbytes > 0) {
  182.         u_char* data = new u_char[totbytes];
  183.         if (TIFFReadRawStrip(tif, strip, data, totbytes) >= 0) {
  184.         /*
  185.          * Pass data to modem, filtering DLE's and
  186.          * being careful not to get hung up.
  187.          */
  188.         beginTimedTransfer();
  189.         rc = putModemDLEData(data, totbytes, bitrev, getDataTimeout());
  190.         endTimedTransfer();
  191.         protoTrace("SENT %d bytes of data", totbytes);
  192.         }
  193.         delete data;
  194.     }
  195.     }
  196.     if (rc)
  197.     rc = sendEOT();
  198.     else
  199.     abortDataTransfer();
  200.     if (flowControl == FLOW_XONXOFF)
  201.     setXONXOFF(FLOW_CURRENT, FLOW_XONXOFF, ACT_DRAIN);
  202.     protoTrace("SEND end page");
  203.     return (rc ? (waitFor(AT_OK) && hangupCode[0] == '\0') : rc);
  204. }
  205.  
  206. /*
  207.  * Receive DLE-escaped data from the modem.
  208.  */
  209. fxBool
  210. Class2ErsatzModem::recvPageDLEData(TIFF* tif)
  211. {
  212.     fxBool prematureEOF = FALSE;
  213.     u_char buf[16*1024];
  214.     int n = 0;
  215.     for (;;) {
  216.     int b = getModemDataChar();
  217.     if (b == EOF) {
  218.         protoTrace("RECV: premature EOF");
  219.         prematureEOF = TRUE;
  220.         break;
  221.     }
  222.     if (b == DLE) {
  223.         b = getModemDataChar();
  224.         if (b == EOF || b == ETX) {
  225.         if (b == EOF) {
  226.             prematureEOF = TRUE;
  227.             protoTrace("RECV: premature EOF");
  228.         }
  229.         break;
  230.         }
  231.         if (b != DLE) {
  232.         if (n == sizeof (buf))
  233.             recvData(tif, buf, sizeof (buf)), n = 0;
  234.         buf[n++] = DLE;
  235.         }
  236.     }
  237.     if (n == sizeof (buf))
  238.         recvData(tif, buf, sizeof (buf)), n = 0;
  239.     buf[n++] = b;
  240.     }
  241.     if (n > 0)
  242.     recvData(tif, buf, n);
  243.     return (prematureEOF);
  244. }
  245.